package cjcast.y2010.qual;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import cjcast.common.CaseConverter;
import cjcast.common.CjInputReader;
import cjcast.common.ReadWriteTextFileJDK7;


/** Store Credit Problem case. */
public class StoreCreditCase {


    /** */
    private static final Logger LOGGER = LogManager
        .getLogger(StoreCreditCase.class);

    /** File reader/writer. */
    private final transient ReadWriteTextFileJDK7 fileUtil = new ReadWriteTextFileJDK7();

    /** Case Size. */
    public static final int CASE_SIZE = 3;


    /**
     * Retrieve the indices from the array of item prices where total is equal
     * to the credit.
     * 
     * @param credit credit amount.
     * @param items item prices.
     */
    int[] getIndeces(final int credit, final int[] items)
    {
        return impl2(credit, items);
    }

    /**
     * Default implementation, straight forward, no optimization.
     * 
     * @param credit credit amount.
     * @param items item prices.
     */
    int[] impl1(final int credit, final int[] items)
    {
        final int[] retval = new int[2];
        Outer: for (int i = 0; i < items.length; i++) {
            for (int j = 0; j < items.length; j++) {
                if (i != j && items[i] + items[j] == credit) {
                    //sort
                    if (i > j) {
                        i = i + j;
                        j = i - j;
                        i = i - j;
                    }
                    retval[0] = i + 1;
                    retval[1] = j + 1;
                    break Outer;
                }
            }
        }
        return retval;
    }

    /**
     * 
     * @param credit credit amount.
     * @param items item prices.
     */
    int[] impl2(final int credit, final int[] items)
    {

        final Map<Integer, Integer> dir = new HashMap<Integer, Integer>();
        for (int index = 0; index < items.length; index++) {
            dir.put(items[index], index);
        }

        final int[] retval = new int[2];
        for (int i = 0; i < items.length; i++) {
            Integer delta = dir.get(credit - items[i]);
            if (delta != null && i != delta.intValue()) {
                //sort
                if (i > delta) {
                    i = i + delta;
                    delta = i - delta;
                    i = i - delta;
                }

                retval[0] = i + 1;
                retval[1] = delta + 1;
                break;
            }
        }
        return retval;
    }

    /**
     * Returns an instance of InputReader.
     * 
     * @param file input file to parse.
     * @throws IOException if error occurs while parsing the file.
     */
    CjInputReader<StoreCreditBean> getNewInput(final File file)
            throws IOException
    {
        return new CjInputReader<StoreCreditBean>(
            file,
            CASE_SIZE,
            new CaseConverter<StoreCreditBean>() {

                @Override
                public StoreCreditBean convert(final String... string)
                {
                    final int credit = Integer.parseInt(string[0]);
                    final String[] pricesStr = string[2].split(" ");
                    final int[] prices = new int[pricesStr.length];
                    for (int i = 0; i < prices.length; i++) {
                        prices[i] = Integer.parseInt(pricesStr[i]);
                    }
                    return new StoreCreditBean(credit, prices);
                }
            });
    }

    /**
     * This will generate the output file for submission to google.
     * 
     * @param inputFile input file.
     * @param outpuFile the result file path.
     * @throws IOException if error occurs while parsing the file.
     */
    public void generateOutput(final File inputFile, final File outpuFile)
            throws IOException
    {
        final StoreCreditCase storeCreditCase = new StoreCreditCase();
        final CjInputReader<StoreCreditBean> smallInputReader = storeCreditCase
            .getNewInput(inputFile);

        final List<String> output = new ArrayList<String>();
        int index = 1;
        for (final StoreCreditBean storeCredit : smallInputReader) {
            final int[] result = storeCreditCase.getIndeces(
                storeCredit.getCredit(),
                storeCredit.getPrices());
            output.add("Case #" + index++ + ": " + result[0] + " " + result[1]);
        }

        getFileUtil().writeLargeTextFile(outpuFile.getAbsolutePath(), output);


    }


    /**
     * This will generate contents of output file for submission.
     * 
     * @param args command line arguments.
     * 
     * @throws IOException if error occurs while parsing the file.
     */
    public static void main(final String... args) throws IOException
    {
        final long start = System.currentTimeMillis();

        final StoreCreditCase storeCreditCase = new StoreCreditCase();
        final String outputSmall = "c:\\A-small-practice.out.txt";
        final String outputLarge = "c:\\A-large-practice.out.txt";

        storeCreditCase.generateOutput(
            new File("c:\\A-small-practice.in"),
            new File(outputSmall));
        storeCreditCase.generateOutput(
            new File("c:\\A-large-practice.in"),
            new File(outputLarge));

        LOGGER.info(System.currentTimeMillis() - start + " ms.");
    }

    public ReadWriteTextFileJDK7 getFileUtil()
    {
        return this.fileUtil;
    }

}
